(十一) UVC调节亮度 您所在的位置:网站首页 曝光 pu光 (十一) UVC调节亮度

(十一) UVC调节亮度

#(十一) UVC调节亮度| 来源: 网络整理| 查看: 265

title: UVC调节亮度 date: 2019/4/23 20:30:00 toc: true

目录UVC调节亮度引入硬件协议速览代码框架属性初始化属性支持查询具体属性值获取具体属性值设置代码实现

UVC调节亮度 引入

摄像头的参数比如亮度等是通过VC接口控制的,具体可以参考APP的调用流程,这里暂时不分析了

xawtv.c: grabber_scan ng_vid_open v4l2_driver.open // v4l2_open get_device_capabilities(h); // 调用VIDIOC_QUERYCTRL ioctl确定是否支持某个属性 /* controls */ for (i = 0; i < MAX_CTRL; i++) { h->ctl[i].id = V4L2_CID_BASE+i; if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i], EINVAL) || (h->ctl[i].flags & V4L2_CTRL_FLAG_DISABLED)) h->ctl[i].id = -1; } 怎么去获得/设置属性? 看drv0-v4l2.c 可见这2个函数: v4l2_read_attr : VIDIOC_G_CTRL v4l2_write_attr : VIDIOC_S_CTRL

直接说结论

ioctl中的VIDIOC_QUERYCTRL来查询是支持的属性,VIDIOC_G_CTRL,VIDIOC_S_CTRL来读取设置具体的属性

硬件协议速览

亮度设置等属性是归属于PU的,我们找到uvc规范中的Processing Unit Descriptor

mark

这里有一个3字节的bmControls指示了所有的属性,1表示支持这个属性,0表示不支持.我们之前读取联合接口描述符可以分析出PU是支持亮度调节的

mark

代码框架

对于硬件的描述,程序在uvc_ctrl.c > uvc_ctrls也描述了这个

将SU,PU,CT,IT等都抽象为entity,这使用16个字节的GUID标识 selector标识了具体的属性,index则指出了在实际的数据位,在亮度中为bit0,这里index=0 size标识了数据的大小,单位为字节,亮度为两个字节,有些属性可能为11位,那么他也占据两个字节,具体有11位在下面另外一个结构体uvc_ctrl_mappings指出 flags表示可读可写等 static struct uvc_control_info uvc_ctrls[] = { { .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_BRIGHTNESS_CONTROL, .index = 0, .size = 2, .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_RANGE | UVC_CTRL_FLAG_RESTORE, }, ..... { .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_ANALOG_LOCK_STATUS_CONTROL, .index = 17, .size = 1, .flags = UVC_CTRL_FLAG_GET_CUR, }, //===================================================================// { .entity = UVC_GUID_UVC_CAMERA, .selector = UVC_CT_SCANNING_MODE_CONTROL, .index = 0, .size = 1, .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR | UVC_CTRL_FLAG_RESTORE, },

这里是另外更详细的一些描述

size标识了使用了上述字节数中的多少位 offset 则是偏移量 v4l2_type提供给APP这是什么数据类型,比如菜单,滑动条等 data_type则是数据的类型 static struct uvc_control_mapping uvc_ctrl_mappings[] = { { .id = V4L2_CID_BRIGHTNESS, .name = "Brightness", .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_BRIGHTNESS_CONTROL, .size = 16, .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_INTEGER, .data_type = UVC_CTRL_DATA_TYPE_SIGNED, }, .... enum v4l2_ctrl_type { V4L2_CTRL_TYPE_INTEGER = 1, V4L2_CTRL_TYPE_BOOLEAN = 2, V4L2_CTRL_TYPE_MENU = 3, V4L2_CTRL_TYPE_BUTTON = 4, V4L2_CTRL_TYPE_INTEGER64 = 5, V4L2_CTRL_TYPE_CTRL_CLASS = 6, V4L2_CTRL_TYPE_STRING = 7, V4L2_CTRL_TYPE_BITMASK = 8, }; /* Data types for UVC control data */ #define UVC_CTRL_DATA_TYPE_RAW 0 #define UVC_CTRL_DATA_TYPE_SIGNED 1 #define UVC_CTRL_DATA_TYPE_UNSIGNED 2 #define UVC_CTRL_DATA_TYPE_BOOLEAN 3 #define UVC_CTRL_DATA_TYPE_ENUM 4 #define UVC_CTRL_DATA_TYPE_BITMASK 5 属性初始化

在uvc_drvier.c > uvc_ctrl_init_device 中会通过USB读取到具体支持哪些属性,并构造一个结构去管理.

最终目的就是实现

读取具体的属性支持,构造uvc_control

将之前统一设置的uvc_ctrls(包含了具体的属性是否可读的信息等),挂载到上述构造的结构中

memcpy(&ctrl->info, info, sizeof(*info)) //>ctrl->info = 某个uvc_control_info数组项

详细的流程如下

uvc_ctrl_init_device // 遍历所有的 pu/eu/ct list_for_each_entry(entity, &dev->entities, list) { struct uvc_control *ctrl; // 取出具体的数据,数据size bmControls = entity->processing.bmControls; bControlSize = entity->processing.bControlSize; // 统计支持的属性个数 for (i = 0; i < bControlSize; ++i) ncontrols += hweight8(bmControls[i]); // 一次性分配n个属性控制结构,到 uvc_control entity->controls = kcalloc(ncontrols, sizeof(*ctrl),GFP_KERNEL); ctrl = entity->controls; // 关联这个 uvc_control(这个刚构造的属性描述) 和 uvc_control_info类型的 uvc_ctrls (统一的描述) uvc_ctrl_init_ctrl // 查询guid 和 index 一致 则关联 if (uvc_entity_match_guid(ctrl->entity, info->entity) &&ctrl->index == info->index) { uvc_ctrl_add_info(dev, ctrl, info); //这里有个关键函数 uvc_control_mapping.get/set 为这个 control 结构具体的数据转换函数 __uvc_ctrl_add_mapping(dev, ctrl, mapping); if (map->get == NULL) map->get = uvc_get_le_value; if (map->set == NULL) map->set = uvc_set_le_value; 属性支持查询

从ioctl入手

uvc_v4l2_do_ioctl case VIDIOC_QUERYCTRL: uvc_query_v4l2_ctrl(chain, arg) uvc_find_control(chain, v4l2_ctrl->id, &mapping) //遍历 entity list_for_each_entry(entity, &chain->entities, chain) //寻找到一个详细的描述 // 这里有指示这个 unit 的详细信息,这个mapping就是 // static struct uvc_control_mapping uvc_ctrl_mappings[] __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next)

也就是说存在这么个流程

设备插入后初始化属性管理结构,这个管理结构会挂载uvc_control_info uvc_ctrls,指示了可读可写等信息 查询属性的时候,可以根据这个找到更详细的uvc_control_mapping uvc_ctrl_mappings[],指示了具体的数据位宽和默认值等 具体属性值获取 VIDIOC_G_CTRL uvc_ctrl_get(chain, &xctrl); // 属性查询,了解具体的操作格式 uvc_find_control // 发起usb传输 获取最大最小值,存到 ctrl->uvc_data 这个是在初始化后分配的内存 uvc_ctrl_populate_cache (UVC_GET_DEF,UVC_GET_MIN,UVC_GET_MAX) uvc_query_ctrl usb_control_msg // 传递给usb uvc_query_ctrl __uvc_query_ctrl usb_control_msg // ... uvc_ctrl_rollback(chain); 具体属性值设置 VIDIOC_S_CTRL uvc_ctrl_set // 属性查询 uvc_find_control // 发起usb传输 获取最大最小值,存到 ctrl->uvc_data 这个是在初始化后分配的内存 if (!ctrl->cached) { //这里如果在读属性的时候获取过就不再发起usb传输获取了 ret = uvc_ctrl_populate_cache(chain, ctrl); //数据转换 min,max,step=get(uvc_ctrl_data..) // 传输usb uvc_query_ctrl __uvc_query_ctrl usb_control_msg uvc_ctrl_commit 代码实现

这里代码的实现难点还是在usb_control_msg的参数确定了,摘录自这里

usb_control_msg() 功能:发送一个简单的控制消息到指定的端点,并等待消息完成或超时; 参数:   dev:指向控制消息所发送的目标USB设备(usb_device)的指针;   pipe:控制消息所发送的目标USB设备的特定端点,调用usb_sndctrlpipe(把指定USB设备的指定端点设置为一个控制OUT端点)或usb_rcvctrlpipe(把指定USB设备的指定端点设置为一个控制IN端点)来创建的;   request:控制消息的USB请求值;   requesttype:控制消息的USB请求类型值; id != V4L2_CID_BRIGHTNESS) return -EINVAL; pipe = usb_rcvctrlpipe(myuvc_udev, 0); type |= USB_DIR_IN; ret = usb_control_msg(myuvc_udev, pipe, GET_CUR, type, PU_BRIGHTNESS_CONTROL id != V4L2_CID_BRIGHTNESS) return -EINVAL; myuvc_set_le_value(ctrl->value, data); pipe = usb_sndctrlpipe(myuvc_udev, 0); type |= USB_DIR_OUT; ret = usb_control_msg(myuvc_udev, pipe, SET_CUR, type, PU_BRIGHTNESS_CONTROL


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有